package com.bluexmicro.android.coroutineble.model

import android.bluetooth.BluetoothGatt
import android.bluetooth.BluetoothGattCharacteristic
import android.bluetooth.BluetoothGattDescriptor
import android.bluetooth.BluetoothGattService
import java.util.*

sealed class BleRequest(
    val value: ByteArray? = null
) {

    open val date = Date()
    open var result = true //默认为正确
    open var errorMessage: String? = null

    internal abstract fun getRequestString(): String

    fun getDesc(): String {
        val reason = errorMessage?.run { "\nReason: $this" }
        val resultStr = if (result) " success." else " failed."
        return if (reason != null) {
            "${getRequestString()} ${resultStr}${reason}"
        } else {
            "${getRequestString()} $resultStr"
        }
    }

    class Connect : BleRequest() {
        override fun getRequestString(): String {
            return "Connect"
        }
    }

    class Disconnect : BleRequest() {
        override fun getRequestString(): String {
            return "Disconnect"
        }
    }

    class DiscoverServices : BleRequest() {
        override fun getRequestString(): String {
            return "Discover services"
        }
    }

    class SetNotification(val characteristic: BluetoothGattCharacteristic, val enable: Boolean) :
        BleRequest() {
        override fun getRequestString(): String {
            val txt = if (enable) "Enable" else "Disable"
            return "$txt notification (${characteristic.uuid})"
        }
    }

    class RequestMTU(val size: Int) : BleRequest() {
        override fun getRequestString(): String {
            return "Request MTU $size"
        }
    }

    class RequestConnectionProperty(val property: Int) : BleRequest() {
        override fun getRequestString(): String {
            return when (property) {
                BluetoothGatt.CONNECTION_PRIORITY_HIGH -> "Request high connection priority"
                BluetoothGatt.CONNECTION_PRIORITY_BALANCED -> "Request balance connection priority"
                BluetoothGatt.CONNECTION_PRIORITY_LOW_POWER -> "Request low power connection priority"
                else -> "Param error"
            }
        }
    }

    class SetPhy(val tx: Int, val rx: Int) : BleRequest() {
        override fun getRequestString(): String {
            return "Set Phy (TX: $tx, RX: $rx)"
        }
    }

    class Read(val characteristic: BluetoothGattCharacteristic) : BleRequest() {
        override fun getRequestString(): String {
            return "Read characteristic (${characteristic.uuid}) "
        }
    }

    class ReadDescriptor(val descriptor: BluetoothGattDescriptor) : BleRequest() {
        override fun getRequestString(): String {
            return "Read descriptor (${descriptor.uuid}) "
        }
    }

    class Write(val characteristic: BluetoothGattCharacteristic, newValue: ByteArray) :
        BleRequest(value = newValue) {
        override fun getRequestString(): String {
            return "Write characteristic (${characteristic.uuid}) "
        }
    }

    class WriteDescriptor(val descriptor: BluetoothGattDescriptor, newValue: ByteArray) :
        BleRequest(value = newValue) {

        override fun getRequestString(): String {
            return "Write descriptor (${descriptor.uuid}) "
        }
    }

    class Other(val msg: String) : BleRequest() {
        override fun getRequestString(): String {
            return msg
        }
    }

}


sealed class BleResponse(val status: Int) {

    open val date = Date()
    fun isSuccess(): Boolean = status == BluetoothGatt.GATT_SUCCESS

    abstract fun getDesc(): String
    abstract fun getValue(): ByteArray?

    class OnConnectionStateChange(val state: ConnectionState) :
        BleResponse(BluetoothGatt.GATT_SUCCESS) {
        override fun getDesc(): String {
            return "Connection State Changed => ${state.name}"
        }

        override fun getValue(): ByteArray? = null
    }

    class OnServicesDiscovered(val services: List<BluetoothGattService>, status: Int) :
        BleResponse(BluetoothGatt.GATT_SUCCESS) {
        override fun getDesc(): String {
            return if (isSuccess()) {
                "Found ${services.size} services"
            } else {
                "Discover failed, Status = $status"
            }
        }

        override fun getValue(): ByteArray? = null
    }

    class OnCharacteristicRead(val characteristic: BluetoothGattCharacteristic, status: Int) :
        BleResponse(status) {
        override fun getDesc(): String {
            return "OnCharacteristicRead (${characteristic.uuid}) status = $status"
        }

        override fun getValue(): ByteArray? = characteristic.value
    }

    class OnCharacteristicWrite(val characteristic: BluetoothGattCharacteristic, status: Int) :
        BleResponse(status) {
        override fun getDesc(): String {
            return "OnCharacteristicWrite (${characteristic.uuid}) status = $status"
        }

        override fun getValue(): ByteArray? = null
    }

    class OnCharacteristicChanged(val characteristic: BluetoothGattCharacteristic) :
        BleResponse(BluetoothGatt.GATT_SUCCESS) {

        override fun getDesc(): String {
            return "OnCharacteristicChanged (${characteristic.uuid})"
        }

        override fun getValue(): ByteArray? = characteristic.value
    }

    class OnDescriptorWrite(
        val descriptor: BluetoothGattDescriptor,
        status: Int,
    ) : BleResponse(status) {
        override fun getDesc(): String {
            return "OnDescriptorWrite (${descriptor.uuid}) status = $status"
        }

        override fun getValue(): ByteArray? = null
    }

    class OnDescriptorRead(
        val descriptor: BluetoothGattDescriptor,
        status: Int,
    ) : BleResponse(status) {
        override fun getDesc(): String {
            return "OnDescriptorRead (${descriptor.uuid}) status = $status"
        }

        override fun getValue(): ByteArray? = descriptor.value
    }

    class OnMtuChanged(
        val mtu: Int,
        status: Int
    ) : BleResponse(status) {
        override fun getDesc(): String = "OnMtuChanged (Size = $mtu) status = $status"

        override fun getValue(): ByteArray? = null
    }

    class OnPhyUpdate(
        val txPhy: Int, val rxPhy: Int, status: Int
    ) : BleResponse(status) {
        override fun getDesc(): String =
            "OnPhyUpdate (txPhy = $txPhy; rxPhy = $rxPhy) status = $status"

        override fun getValue(): ByteArray? = null
    }
}